/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Model;

import java.util.ArrayList;
import java.util.Random;

/**
 * Class the controls the specifics on the intersection such as vertical and horizontal lanes, filler.
 * @author Luke
 */
public class Intersection {

    private Number numVStreet; //Setup intersection specifics
    private Number numHStreet;
    private Number probVCars;
    private Number probHCars;
    private ArrayList<ArrayList> vertArray = new ArrayList();
    private ArrayList<ArrayList> horzArray = new ArrayList();
    private int n_filler = 10;

    /**
     * Constructor for the intersection
     * @param streetValues The value contains the number of lanes (horizontal, verticaL) and probability of new cars
     */
    public Intersection(ArrayList<Number> streetValues) {
        setNumHStreet(streetValues.get(0).intValue());
        setNumVStreet(streetValues.get(1).intValue());
        setProbHCars(streetValues.get(2).floatValue());
        setProbVCars(streetValues.get(3).floatValue());
    }

    /**
     * Gets the amount of filler spaces each side of the intersection
     * @return A number that is the amount of filler spaces
     */
    public int getN_filler() {
        return n_filler;
    }

    /**
     * Sets the number of horizontal streets in the intersection
     * @param numHStreet One value is passed in, it is the number of horizontal streets
     */
    public void setNumHStreet(Number numHStreet) {
        this.numHStreet = numHStreet;
    }

    /**
     *Sets the number of vertical streets in the intersection
     * @param numVStreet One value is passed in, it is the number of vertical streets
     */
    public void setNumVStreet(Number numVStreet) {
        this.numVStreet = numVStreet;
    }

    /**
     * Sets the probability of a car entering a the horizontal street
     * @param probHCars Takes one value, the probability of a car
     */
    public void setProbHCars(Number probHCars) {
        this.probHCars = probHCars;
    }

    /**
     * Sets the probability of a car entering a the vertical street
     * @param probVCars Takes one value, the probability of a car
     */
    public void setProbVCars(Number probVCars) {
        this.probVCars = probVCars;
    }

    /**
     * Method to return the Horizontal ArrayList
     * @return The horizontal ArrayList
     */
    synchronized public ArrayList<ArrayList> getHorzArray() {
        return horzArray;
    }

    /**
     * Method to return the vertical ArrayList
     * @return The vertical ArrayList
     */
    synchronized public ArrayList<ArrayList> getVertArray() {
        return vertArray;
    }

    /**
     * Method to get the number of horizontal streets
     * @return The number of horizontal streets
     */
    public Integer getNumHStreet() {
        return numHStreet.intValue();
    }

    /**
     * Method to get the number of horizontal streets
     * @return The number of horizontal streets
     */
    public Integer getNumVStreet() {
        return numVStreet.intValue();
    }

    /**
     * Method to get the probability of a car entering the horizontal street
     * @return Probability of a car entering the horizontal street
     */
    public Float getProbHCars() {
        return probHCars.floatValue();
    }

    /**
     *Method to get the probability of a car entering the horizontal street
     * @return Probability of a car entering the horizontal street
     */
    public Float getProbVCars() {
        return probVCars.floatValue();
    }

    /**
     * Method used to generate the Horizontal and Vertical ArrayLists
     * @param aNum Is the the amount of filler spaces on either side of the intersection lanes
     */
    public void generate_Lanes(int aNum) {
        n_filler = aNum;

        for (int i = 0; i < ((n_filler * 2) + 2); i++) {
            vertArray.add(generate_VLane()); //make array containing the vertical lane gap
        }

        for (int i = 0; i < numHStreet.intValue(); i++) {
            horzArray.add(generate_HLane()); //add arraylist containing one horizontals running lane a set num of times
        }
    }

    /**
     * Method to specifically generate one all the vertical lanes row by row
     * @return An arrayList of only vertical rows.
     */
    public ArrayList generate_VLane() {
        ArrayList tempList_V = new ArrayList();
        for (int i = 0; i < numVStreet.intValue(); i++) {
            tempList_V.add(" "); //make blank lanes
        }
        return tempList_V;
    }

    /**
     *
     * Method to specifically generate one all the horizontal lanes row by row
     * @return An arrayList of only horizontal rows.
     */
    public ArrayList generate_HLane() {
        ArrayList tempList_H = new ArrayList();
        int spaces = ((n_filler * 2) + 2) + numHStreet.intValue(); //to get to number of spaces for horizontal lanes
        for (int i = 0; i < spaces; i++) { //for every space required make a new element in the array
            tempList_H.add(" ");
        }
        return tempList_H;
    }

    private String generate_Fill(String character) { //a character is passed in and based on number of filler
        String tempString = "";
        for (int i = 0; i < n_filler; i++) {
            tempString += character; //a temp string is created to hold the filler
        }
        return tempString; //the filler is returned
    }

    /**
     * Method that is used to generate cars into the intersection
     * @param carDirection Determines whether the car will be made into the horizontal or vertical intersection
     * @return An ArrayList of the freshly generated cars for the corresponding intersection array
     */
    public ArrayList makeCars(String carDirection) {
        if (carDirection.equals("vertical")) {


            int overflow_Flag = 0; //counter for measuring fullness of vertical lanes
            ArrayList newVCars = new ArrayList();
            Random rnd = new Random(); //new instance of object random
            Float compareFloat = 0.0f; //instatiate a float

            for (int i = 0; i < numVStreet.intValue(); i++) { //for each lane
                if (vertArray.get(1).get(i).toString().equals("c")) { //if elem in that lane is little c
                    overflow_Flag++; //increase the counter
                }
            }

            for (int i = 0; i < numVStreet.intValue(); i++) { // for each horizontal lane
                newVCars.add(" "); //a new car is made
            }
            compareFloat = rnd.nextFloat(); //generate random number
            if (compareFloat <= probVCars.floatValue() && overflow_Flag != numVStreet.intValue()) { //if the random number is less than or equal to the probability of a new car
                newVCars.set(rnd.nextInt(numVStreet.intValue()), new Car("vertical"));
            }
            overflow_Flag = 0; //reset the over flow flag
            return newVCars;
        } else if (carDirection.equals("horizontal")) {

            int overflow_Flag = 0; //counter that declares the fullness of the intersection
            for (int i = 0; i < horzArray.size(); i++) {
                if (horzArray.get(i).get(1).toString().equals("C")) { //if car is in elem 2 of intersection
                    overflow_Flag++; //increase the flag
                }
            }

            ArrayList newHCars = new ArrayList();
            Random rnd = new Random(); //new instance of object random
            Float compareFloat = 0.0f;

            for (int i = 0; i < numHStreet.intValue(); i++) { // for each horizontal lane
                newHCars.add(" "); //a new elem
            }

            compareFloat = rnd.nextFloat();
            if (compareFloat <= probHCars.floatValue() && overflow_Flag != numHStreet.intValue()) { //if the random number is less than or equal to the probability of a new car
                newHCars.set(rnd.nextInt(numHStreet.intValue()), new Car("horizontal")); //put a car in a random lane
            } else {
                newHCars = null;
            }
            overflow_Flag = 0; //reset counter
            if (newHCars != null) {
                return newHCars;
            }

        }
        return null;
    }

    /**
     *Method used in the text based version of the simulation to draw. the intersection
     */
    public void drawIntersection() {

        String blanks = generate_Fill(" "); //makes a fill of blank spaces i.e "             "
        String dashes = generate_Fill("-"); //makes a fill of dashes i.e ------------
        String filler = blanks; //used for filling in the intersectiRed outline

        for (int i = 0; i < vertArray.size(); i++) { //for loop for printing surround and first half of vertical intersection.

            if (i == (n_filler - 1)) { //when up to printing the 9th line
                filler = dashes; //print dashes instead of filler
            } else if (i == n_filler) {
                filler = blanks;
                break; //if i reaches the amount of filler break the loop
            }

            System.out.print(filler + "|");
            for (int j = 0; j < vertArray.get(i).size(); j++) { //display the horizontal gap
                System.out.print(vertArray.get(i).get(j)); //prints current index of nested array
            }
            System.out.print("|" + filler);
            System.out.print("\n");
        }
        for (int i = 0; i < horzArray.size(); i++) { //for loops in for loops used for outputing horzontal ArrayList
            for (int j = 0; j < horzArray.get(i).size(); j++) {
                System.out.print(horzArray.get(i).get(j));
            }
            System.out.print("\n");
        }

        for (int i = 0; i < vertArray.size(); i++) { //for loop that controls printing the surrounds and second half of the vertical intersection
            if (i == 0) {
                filler = dashes;
            } else if (i == n_filler) {
                filler = blanks;
                break; //if i reaches the amount of n_filler break the loop
            } else {
                filler = blanks;
            }
            ArrayList temp = (ArrayList) vertArray.get(i + n_filler); //make an alias for nested referencing and increase index by 10
            System.out.print(filler + "|");
            for (int j = 0; j < temp.size(); j++) { //display the horizontal gap
                System.out.print(temp.get(j)); //prints current index of nested array
            }
            System.out.print("|" + filler);
            System.out.print("\n");
        }
        System.out.println("\n");
    }

    /**
     * The method used to move cars in the vertical array of the intersection
     * @param v_Lights The string passed in that states whether the vertical lights are green or red
     */
    public void moveVCars(String v_Lights) {
        for (int i = vertArray.size() - 1; i > -1; i--) {
            for (int j = 0; j < vertArray.get(0).size(); j++) {
                if (vertArray.get(i).get(j).toString().startsWith("c")) { //if elem equals Car then
                    if (i == vertArray.size() - 1) {
                        vertArray.get(i).set(j, " "); //if the current arrayllist is last arraylist with Car set to " "
                    } else if (i == (n_filler - 1) && v_Lights.equals("Green")) {
                        horzArray.get(0).set(n_filler + 1 + j, vertArray.get(i).get(j)); //****move Car from Vertical to Horizontal
                        vertArray.get(i).set(j, " "); //remove Car from where it used to be
                    } else if (i == (n_filler - 1) && v_Lights.equals("Red")) { //if elem up to intersection an lights are Red then
                        //Do nothing
                    } else if (vertArray.get(i + 1).get(j).toString().startsWith("c")) { //if the space being moved to is a car
                        for (int k = 0; k < vertArray.get(0).size(); k++) { //check other lanes from 0 - max
                            if (vertArray.get(i + 1).get(k).equals(" ")) { //if the elem is blank
                                vertArray.get(i + 1).set(k, vertArray.get(i).get(j)); //****move a car there
                                vertArray.get(i).set(j, " "); //reset the car's original position to blank
                            }
                        }
                    } else {
                        vertArray.get(i + 1).set(j, vertArray.get(i).get(j)); //****move Car to next array list
                        vertArray.get(i).set(j, " "); //set elem moved from to a " "
                    }
                }
                if (i == n_filler && vertArray.get(n_filler).get(j).equals(vertArray.get(i).get(j))) {
                    vertArray.get(n_filler).set(j, vertArray.get(i).get(j)); //transform little c into big C
                }
            }
        }
    }

    /**
     * The method used to move cars in the horizontal array of the intersection
     * @param h_Lights The string passed in that states whether the horizontal lights are green or red
     */
    public void moveHCars(String h_Lights) {
        for (int i = horzArray.size() - 1; i > -1; i--) {
            for (int j = horzArray.get(0).size() - 1; j > -1; j--) {
                if (horzArray.get(i).get(j).toString().startsWith("C")) { //if elem equals C then
                    if (j == horzArray.get(0).size() - 1) {
                        horzArray.get(i).set(j, " ");
                    } else if (h_Lights.equals("Red") && j == n_filler) {
                        //DO NOTHING
                    } else if (horzArray.get(i).get(j + 1).toString().startsWith("C")) { //if the space being moved to is a car
                        for (int k = 0; k < horzArray.size(); k++) { //check other lanes from 0 - max
                            if (horzArray.get(k).get(j + 1).toString().equals(" ")) { //if the elem is blank
                                horzArray.get(k).set(j + 1, horzArray.get(i).get(j)); //move a car there
                                horzArray.get(i).set(j, " "); //reset the car's original position to blank
                            }
                        }
                    } else {
                        horzArray.get(i).set(j + 1, horzArray.get(i).get(j)); //Make next elem equal to C
                        horzArray.get(i).set(j, " "); //Make current elem equals to a " "
                    }
                } else if (horzArray.get(i).get(j).toString().startsWith("c")) { //if the elem equals a small c
                    if (i != horzArray.size() - 1) { //and the elem is in the last lane
                        horzArray.get(i + 1).set(j, horzArray.get(i).get(j)); //move the vertical car
                        horzArray.get(i).set(j, " "); //reset the elem to " "
                    } else {
                        vertArray.get(n_filler).set(j - (n_filler + 1), horzArray.get(i).get(j)); //move elem from HorzArray to VertArray
                        horzArray.get(i).set(j, " ");
                    }

                }

            }
        }
    }
}
